//
//  main.m
//  07-内存管理
//
//  Created by dllo on 16/7/12.
//  Copyright © 2016年 dllo. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Man.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 内存问题
        // 一,内存泄漏或者叫内存溢出
        // 解释:内存过多导致溢出,会产生Crash
        // 二,野指针
        // 解释:指针指向位置地域,指向一块被释放的内存
        // 野指针:返回字符串,如:0f0x0afksdja,数组,字典等
        // 内存管理方式
        // 1.垃圾回收机制:只有Mac上有
        // IOS
        // 2.MRC:手动管理引用计数
        // 3.ARC :自动管理引用计数(现在常用)
        // 注意:ARC基于MRC进行管理,系统能帮程序员添加了内存管理的内容
        // 1.MRC (情况下)
        // retain .alloc .copy 需要进行内存管理,(看不到就不需要管理,因为他们内部封装了持有和释放机制)
        // 内存管理:引用计数(计数器)
        // 有retain .alloc .copy 需要对引用计数 + 1 ,
        // 有release . autorelease .会对引用计数 - 1
        // 当对象的引用计数为0的时候,系统会调用对应的dealloc方法
        // 注意你对对象操作完成后在做释放
        Man *man = [[Man alloc] init];
        NSLog(@"%ld",[man retainCount]);
        [man retain];
        [man release];
        NSLog(@"%ld",[man retainCount]);
        // 集合类型会对对象引用计数加一
        // addObject 对 对象进行引用计数 + 1
        // removeObject 对队形进行引用计数 - 1
        NSMutableArray *array = [NSMutableArray arrayWithObjects:man, nil];
        NSLog(@"向数组添加后的引用计数%ld",man.retainCount);
        [array removeObject:man];
        NSLog(@"向数组移除后的引用计数%ld",man.retainCount);
        // 2.ARC
        // strong(强引用,计数 + 1) weak(应用于对象类型(NSObject 的子类)弱引用,对象释放时,会自动置空)
        // copy (把对象拷贝一份,原来的引用计数不变,新的 + 1);
        // MRC
        // retain(计数 + 1) assign (应用简单的基本类型,不会产生引用计数)
        // 协议
        // 1.声明协议(Gay.h) 只声明不实现
        // 2.签订协议(Man.h) 签订
        // 3.实现协议方法(Man.m) 实现必须实现的方法,或者可选的方法
       
        Man *newMan = [man copy];
        // 如果想实现对象的拷贝
        // 1.签订协议NSCopying
        // 2.实现协议方法copyWithZone
        NSLog(@"拷贝后\n%@ 拷贝前\n%@ ",newMan,man);
     
        // 浅拷贝 只拷贝指针,不拷贝属性
        // 深拷贝 全部拷贝,包括属性
        
        // 字符串可以拷贝因为它已经内部实现了NSCopying协议,字符串一律用copy修饰
        
        
        // KVC Key-Value_Coding 键值编码 间接访问%%成员%%的方式
        // 只要是NSObject的子类就可以访问(5个)
        // valueForKey
        // valueForKeyPath
        // setValue:ForKey
        // setValue:ForKeyPath
        // setValuesForKeysWithDictionary
        newMan.name = @"眼望穿";
        newMan.sexual = @"骚男";
        id name = [newMan valueForKey:@"name"];
        NSLog(@"%@",name);
        [newMan setValue:@"风徐来" forKey:@"name"];
        NSLog(@"%@",newMan.name);
        // valueForKeyPath 通过成员的成员访问
        Man *gayMan = [[Man alloc] init];
        gayMan.gayBoy = newMan;
        id boyName = [gayMan valueForKeyPath:@"gayBoy.name"];
        NSLog(@"+++++%@",boyName);
        [gayMan setValue:@"格斗" forKeyPath:@"gayBoy.name"];
        NSLog(@"-----%@",gayMan.gayBoy.name);
        // 可变字典可用setValue:ForKey,因为可以改变
        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        [dic setValue:@"老友记" forKey:@"dicName"];
        NSLog(@"%@",dic);
        
//        NSDictionary *dic1 = [NSDictionary dictionary];
//        [dic1 setValue:@"蛇蝎美人" forKey:@"Americal"];
//        NSLog(@"不可变字典不行:%@",dic1);
      
        NSDictionary *dic2 = [[NSDictionary alloc] initWithObjectsAndKeys:@"adfafa111", @"id", @"的规划反馈及案发",@"description", nil];
        Man *dicMan = [[Man alloc] init];
        [dicMan setValuesForKeysWithDictionary:dic2];
        // 当调用setValuesForKeysWithDictionary的时候会调用setValue:(id)value forUndefinedKey 方法,在此方法里面重写 键值对的匹配(不重写就会崩溃),dicMan就可以通过属性访问id 的value 和description 的value
        NSLog(@"\nmId = %@\n -- \nmDexcription = %@",dicMan.mId,dicMan.mDescription);
        // 在bulid phases下的编译source下
        // 如果在ARC工程下使用MRC的文件
        // -fno-objc-arc
        // 在MRC工程下使用ARC的文件
        // -fobjc-arc
    }
    return 0;
}
